﻿#import os
#import sys




# Настройка вывода ошибок в файл

# Определяется текущая директория

#__dir__ = os.path.dirname(os.path.abspath(__file__))
#path_error = os.path.join(__dir__, "so_test_error.log")

# Вывод ошибок перенаправляется в файл error.log в текущей директории

#sys.stderr = open(path_error, 'a')


import postgresql.driver as pg_driver
import cymysql
import fdb
import pypyodbc
import cx_Oracle

class db:
	"This class connects and disconnects db"
	#print (self.__doc__)
	#beginning of class suite
	def __init__(self):
		self.driver=None
		self.user=None
		self.passwd=None
		self.host=None
		self.port=None
		self.charset=None
		self.db=None
		self.sid=None
		self.dsn=None
		self.cstring=None
		self.state=False
		self.log=None
		self.conn=None
		self.cursor=None

	def open(self):
		"This function opens connection to db"
		#print (self.open.__doc__)
		return
		
	def connect(self):
		"This function is a wrapper for open function"
		#print (self.connect.__doc__)
		#beginning of function suite
		if self.state==False:
			self.open()
			self.state=True
			self.log='Connected'
		else:
			self.log='Already connected'
		#end of function suite
		return 
	
	def close(self):
		"This function closes connection to db"
		#print (self.close.__doc__)
		self.conn.close()
		return
	
	def disconnect(self):
		"This function is a wrapper for close function"
		#print (self.disconnect.__doc__)
		#end of function suite
		if self.state==True:
			self.close()
			self.conn=None
			self.cursor=None
			self.state=False
			self.log='Disconnected'
		else:
			self.log='Already disconnected'
		#end of function suite
		return
	

	class relations:
		"This class counts and select records for db relations"
		#beginning of class suite
		#print (relations.__doc__)
		#Инициализация:
		def __init__(self):
			self.log=None
			self.db=None
			self.variable=None

		def type(self,type):
			'Function returns db specific type sign'
			return

		def catalogue(self, type):
			'Function returns sql string for the catalogue'
			return
		
		def field(self, type):
			'Function returns sql string for the field'
			return
		
		def list(self, names):
			'Function returns sql string for the list of names'
			return "('"+"','".join(names)+"')"

		def CountString(self, type, names):
			'Function returns sql string for count'
			#Если аргумент names не равен ['']
			if names!=['']:
				string='SELECT COUNT(*) FROM '+self.catalogue(type)+self.field(type)+' IN '+self.list(names)
			else:
				string='SELECT COUNT(*) FROM '+self.catalogue(type)
			return string
	
		def CountlikeString(self, type):
			'Function returns sql string for countlike'
			return 'SELECT COUNT(*) FROM '+self.catalogue(type)+self.field(type)+' LIKE '+self.variable
		
		def SelectString(self, type, names):
			'Function returns sql string for select'
			#Если аргумент names не равен ['']
			if names!=['']:
				string='SELECT * FROM '+self.catalogue(type)+self.field(type)+' IN '+self.list(names)
			else:
				string='SELECT * FROM '+self.catalogue(type)
			return string

		def SelectlikeString(self, type):
			'Function returns sql string for selectlike'
			return 'SELECT * FROM '+self.catalogue(type)+self.field(type)+' LIKE '+self.variable

		def executer(self, string, variable=None):
			return

		#Определяется базовая функция подсчета количества таблиц и видов
		def count(self,type,names):
			'''Function counts relations'''
			#beginning of function suite
			#print(self.count.__doc__)
			#Выполняется подключение к базе данных
			self.db.connect()
			#Переменной result присваивается результат подсчета
			result=self.executer(self.CountString(type, names))[0][0]
			#Закрывается подключение к базе данных
			self.db.disconnect()
			#В переменную класса log записывается лог
			self.log='counted'
			#end of function suite
			#Функция возвращает число таблиц и видов с заданными именами
			return result
		
		#Определяется базовая функция подсчета количества похожих таблиц и видов
		def countlike(self,type,names):
			'''Function counts like relations'''
			#beginning of function suite
			#print(self.countlike.__doc__)
			#Переменной result присваивается ноль
			result=0
			#Выполняется подключение к базе данных
			self.db.connect()
			for name in names:
				#К значению переменной name добавляются %
				name='%'+name+'%'
				#К переменной result прибавляется результат подсчета строк с заданным именем
				result=result+self.executer(self.CountlikeString(type), name)[0][0]
			#Закрывается подключение к базе данных
			self.db.disconnect()
			#В переменную класса log записывается лог
			self.log='counted'
			#end of function suite
			#Функция возвращает число таблиц и видов с похожими именами
			return result

		#Определяется базовая функция выборки записей для таблиц и видов
		def select(self,type,names):
			'''Function counts relations'''
			#beginning of function suite
			#print(self.select.__doc__)
			#Выполняется подключение к базе данных
			self.db.connect()
			#Переменной result присваивается результат выборки
			result=self.executer(self.SelectString(type, names))
			#Закрывается подключение к базе данных
			self.db.disconnect()
			#В переменную класса log записывается лог
			self.log='selected'
			#end of function suite
			#Функция возвращает записи для таблиц и видов с заданными именами
			return result

		#Определяется базовая функция выборки записей для похожих таблиц и видов
		def selectlike(self,type,names):
			'''Function selects like relations'''
			#beginning of function suite
			#print(self.selectlike.__doc__)
			#Переменной query присваивается None
			result=[]
			#Выполняется подключение к базе данных
			self.db.connect()
			for name in names:
				#К значению переменной name добавляются %
				name='%'+name+'%'
				#К переменной result прибавляется результат выборки
				result=result+self.executer(self.SelectlikeString(type), name)
			#Закрывается подключение к базе данных
			self.db.disconnect()
			#В переменную класса log записывается лог
			self.log='selected'
			#end of function suite
			#Функция возвращает записи для видов и таблиц с похожими именами
			return result

		#Определяется функция подсчета количества таблиц
		def CountTables(self,names=['']):
			'''Function counts tables'''
			#beginning of function suite
			#print(self.CountTables.__doc__)
			#end of function suite
			#Функция возвращает число таблиц с заданными именами
			return self.count(self.type('t'),names)

		#Определяется функция подсчета количества видов
		def CountViews(self,names=['']):
			'''Function counts views'''
			#beginning of function suite
			#print(self.CountViews.__doc__)
			#end of function suite
			#Функция возвращает число видов с заданными именами
			return self.count(self.type('v'),names)

		#Определяется функция подсчета количества похожих таблиц
		def CountlikeTables(self,names=['']):
			'''Function counts tables'''
			#beginning of function suite
			#print(self.CountlikeTables.__doc__)
			#end of function suite
			#Функция возвращает число таблиц с похожим именами
			return self.countlike(self.type('t'),names)

		#Определяется функция подсчета количества похожих видов
		def CountlikeViews(self,names=['']):
			'''Function counts views'''
			#beginning of function suite
			#print(self.CountlikeViews.__doc__)
			#end of function suite
			#Функция возвращает число видов с похожим именами
			return self.countlike(self.type('v'),names)

		#Определяется функция выборки таблиц
		def SelectTables(self,names=['']):
			'''Function selects tables'''
			#beginning of function suite
			#print(self.SelectTables.__doc__)
			#end of function suite
			#Функция возвращает выборку таблиц с заданными именами
			return self.select(self.type('t'),names)

		#Определяется функция выборки видов
		def SelectViews(self,names=['']):
			'''Function selects views'''
			#beginning of function suite
			#print(self.SelectViews.__doc__)
			#end of function suite
			#Функция возвращает выборку видов с заданными именами
			return self.select(self.type('v'),names)

		#Определяется функция выборки похожих таблиц
		def SelectlikeTables(self,names=['']):
			'''Function selects like tables'''
			#beginning of function suite
			#print(self.SelectlikeTables.__doc__)
			#end of function suite
			#Функция возвращает выборку таблиц с похожими именами
			return self.selectlike(self.type('t'),names)

		#Определяется функция выборки похожих видов
		def SelectlikeViews(self,names=['']):
			'''Function selects like views'''
			#beginning of function suite
			#print(self.SelectlikeViews.__doc__)
			#end of function suite
			#Функция возвращает выборку видов с похожими именами
			return self.selectlike(self.type('v'),names)

		#end of class relations suite

	class view:
		"This class is a base class to manipulate a view"
		#beginning of class suite
		#print (View.__doc__)
		#Инициализация методов класса
		def __init__(self):
			self.db=db()
			self.relations=db.relations()
			self.log=None
			self.name=''
			self.fields=[]
			self.query=''
			self.param=''
		
		def SqlName(self, name):
			"Function returns sql string for the view name"
			return 'X_OASUP_SO'+name
		
		def SqlFields(self, fields):
			"Function returns sql string for the view fields"
			return ' '+'('+', '.join(fields)+')'
			
		def SqlCreate(self, name, fields, query):
			"Function returns sql string for the view create query"
			return "CREATE"+self.param+"VIEW "+self.SqlName(name)+self.SqlFields(fields)+" AS "+query
			
		def SqlDrop(self, name):
			"Function returns sql string for the view drop query"
			return "DROP VIEW "+self.SqlName(name)
			
		def count(self, name):
			'''Function counts views with the name of the view'''
			#beginning of function suite
			#print(self.count.__doc__)
			#end of function suite
			#Функция возвращает результат выполнения функции self.FdbArticlesToImport.CountViews() с именем вида в качестве аргумента
			return self.relations.CountViews([self.SqlName(name)])
			
		def create(self, name, fields, query):
			'''Function creates the view '''
			#beginning of function suite
			#print(FdbArticlesToImport.create.__doc__)
			#Подсчетывается количество видов с данным именем
			before=self.count()
			#Если количество=0
			if before==0:
				#Выполняется подключение к базе данных
				self.fdb.connect()
				# Выполняется запрос на создание вида в Firebird:
				self.fdb.cursor.execute(self.SqlCreate(name, fields, query))
				#commit
				self.fdb.conn.commit()
				#Закрывается подключение к базе данных
				self.fdb.disconnect()
				#Подсчетывается количество видов с данным именем
				result=self.count(name)-before
				#В переменную класса log записывается лог
				self.log='created'
			else:
				#Переменной result присваивается нулевое значение
				result=0
				#В переменную класса log записывается лог
				self.log='exists'
			#end of function suite
			#Функция возвращает количество созданных видов
			return result

		def drop(self, name):
			'''Function drops the view'''
			#beginning of function suite
			#print(FdbArticlesToImport.drop.__doc__)
			#Подсчетывается количество видов с данным именем
			before=self.count()
			#Если количество не равно нулю:
			if before!=0:
				#Выполняется подключение к базе данных
				self.fdb.connect()
				# Выполняется запрос на удаление вида в Firebird:
				self.fdb.cursor.execute(self.SqlDrop(name))
				#commit
				self.fdb.conn.commit()
				#Закрывается подключение к базе данных
				self.fdb.disconnect()
				#Подсчетывается количество видов с данным именем
				result=before-self.count(name)
				self.log='droped'
			else:
				#Переменной result присваивается нулевое значение
				result=0
				#В переменную класса log записывается лог
				self.log='does not exist'
			#end of function suite
			#Функция возвращает количество уничтоженных видов
			return result
		
		#end of class view suite

	#end of class db suite


#Вывод ошибок возвращается "в исходное положение"

#sys.stderr.close()
#sys.stderr = sys.__stderr__